﻿using Mengsk.ProxyDelivery.Domain;
using Mengsk.ProxyDelivery.Service;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Mengsk.ProxyDelivery.Service.Spider
{
    public abstract class SpiderBase
    {
        public event EventHandler<SpiderMessageEventArgs> Message;

        public event EventHandler<SpiderProgressEventArgs> Progress;

        public event EventHandler<SpiderStartEventArgs> Start;

        public event EventHandler<SpiderStopEventArgs> Stop;

        public abstract string Name { get; }

        public abstract SpiderType SpiderType { get; }

        public string URL { get; set; }

        public bool IsRunning { get; private set; }

        protected bool isStop = false;

        protected StringBuilder errorMessage = new StringBuilder();

        public string ErrorMessage { get { return this.errorMessage.ToString(); } }

        protected void OnMessage(string message)
        {
            if (this.Message != null)
            {
                this.Message(this, new SpiderMessageEventArgs(message));
            }
        }

        protected void OnProgress(int current, int total)
        {
            if (this.Progress != null)
            {
                this.Progress(this, new SpiderProgressEventArgs(current, total));
            }
        }

        protected void OnStart()
        {
            if (this.Start != null)
            {
                this.Start(this, new SpiderStartEventArgs());
            }
        }

        protected void OnStop()
        {
            if (this.Stop != null)
            {
                this.Stop(this, new SpiderStopEventArgs());
            }
        }

        protected string GetContentString(string html, string mark, string header)
        {
            //找div前缀
            int index = html.IndexOf(mark, 0);
            if (index < 0)
            {
                throw new Exception("解析文档失败,无法找到" + header);
            }

            while (html[--index] != '<' && index >= 0) ;

            if (index < 0)
            {
                throw new Exception("搜索前缀" + header + "失败");
            }

            //搜索后缀
            int markCount = 1;
            int lastDivIndex = index;
            try
            {
                while (markCount > 0)
                {
                    lastDivIndex = html.IndexOf(header, lastDivIndex + header.Length);
                    if (html[lastDivIndex - 1] == '/')
                    {
                        markCount--;
                    }
                    else if (html[lastDivIndex - 1] == '<')
                    {
                        markCount++;
                    }
                    else
                    {
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                throw ex;
            }

            string divcontent = html.Substring(index, lastDivIndex - index + 4);
            divcontent = divcontent.Replace("&", "&amp;").Replace("class=\"\"", "").Replace("\"\">", "\">");//go2上的颜色处问题,需要处理,其值为:<li title="颜色:黑色"">
            return divcontent;
        }

        protected string RemoveUnInvalidChars(string content)
        {
            StringBuilder newContent = new StringBuilder(content);
            //删除""之前的非法字符，替换成空格
            int startIndex = content.IndexOf('=');
            while (startIndex >= 0 && startIndex < content.Length)
            {
                //过滤空格
                while (content[++startIndex] == ' ' && startIndex < content.Length) ;

                if (startIndex >= content.Length)
                {
                    break;
                }
                //=号后面，不是合法的数据，继续查找下一个=号
                if (content[startIndex] != '\'' && content[startIndex] != '\"')
                {
                    continue;
                }

                int endIndex = content.IndexOfAny(new char[] { '\'', '\"' }, startIndex + 1);
                if (endIndex >= 0)
                {
                    int i = startIndex + 1;
                    bool replace = false;
                    while (i < endIndex)
                    {
                        if (content[i] == '<' || content[i] == '>')
                        {
                            newContent[i] = ' ';
                            replace = true;
                        }
                        i++;
                    }
                    if (replace)
                    {
                        newContent = newContent.Replace(content.Substring(startIndex + 1, endIndex - startIndex - 1), newContent.ToString(startIndex + 1, endIndex - startIndex - 1));
                    }
                    startIndex = content.IndexOf('=', endIndex + 1);
                }
                else
                {
                    break;
                }
            }

            return newContent.ToString();
        }

        protected XDocument GetContentAsXml(string html, string mark, string header)
        {
            string content = this.GetContentString(html, mark, header);
            try
            {
                return XDocument.Parse(content);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("提取XML文件失败异常信息:" + ex.Message + Environment.NewLine + "文件内容:" + content);
                string newContent = RemoveUnInvalidChars(content);
                Debug.WriteLine("移出异常后的XML内容为:" + newContent);
                return XDocument.Parse(newContent);
            }
        }

        protected void AppendErrorMessage(string message)
        {
            this.errorMessage.AppendLine(DateTime.Now + ": " + message);
        }

        protected abstract void DoSycVendor(VendorService vendorService);

        protected abstract void DoSycGoodss(Vendor[] vendors, ShoesService shoesService);

        //下载商品
        public abstract Shoes[] GetVendorShoes(Vendor vendor);

        public abstract Shoes[] GetVendorShoes(Vendor vendor, string number);

        public void SycVendor(VendorService vendorService)
        {
            try
            {
                this.IsRunning = true;
                this.isStop = false;
                this.errorMessage.Clear();
                this.OnStart();
                this.DoSycVendor(vendorService);
            }
            finally
            {
                this.IsRunning = false;
                this.isStop = true;
                this.OnStop();
            }
        }

        public void SycGoodss(Vendor[] vendors, ShoesService shoesService)
        {
            try
            {
                this.IsRunning = true;
                this.isStop = false;
                this.errorMessage.Clear();
                this.OnStart();
                this.DoSycGoodss(vendors, shoesService);
            }
            finally
            {
                this.IsRunning = false;
                this.isStop = true;
                this.OnStop();
            }
        }

        public void StopSyc()
        {
            this.isStop = true;
        }

        public static SpiderBase CreateSpider(int type)
        {
            SpiderType stype = (SpiderType)type;
            if (stype == SpiderType.GO2)
            {
                return new Go2.Go2Spider();
            }

            throw new Exception("未能认识相应爬的类型");
        }
    }
}
